//-----------------------------------------------------------------------------
// File: PositionGraphics.cs
//
// Copyright (c) Dmitry Shuklin. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace Cerebrum.Direct3D.Drawing
{
	/// <summary>
	/// Summary description for PositionGraphics.
	/// </summary>
	internal class PositionGraphics: Cerebrum.Direct3D.Drawing.Graphics
	{
		public PositionGraphics(Microsoft.DirectX.Direct3D.Device device):base(device)
		{
#warning "debug disabled"
			throw new System.Exception("debug disabled");
		}

		
		private static object g_FieldDrawRectIndexBuffer = new object();
		private static IndexBuffer GetDrawRectIndexBuffer(Microsoft.DirectX.Direct3D.Device device)
		{
			IndexBuffer _IndexBuffer = DeviceObjects[device, g_FieldDrawRectIndexBuffer] as IndexBuffer;
			if(_IndexBuffer==null)
			{
				short[] indices = new short[] {0,1,2,3,2,1,0,1,3,2,0};
				_IndexBuffer = new IndexBuffer(typeof(short), indices.Length, device, Usage.WriteOnly, Pool.SystemMemory);
				_IndexBuffer.SetData(indices, 0, 0);
				DeviceObjects[device, g_FieldDrawRectIndexBuffer] = _IndexBuffer;
			}
			return _IndexBuffer;
		}


		public override void DrawLine(System.Drawing.PointF p1, System.Drawing.PointF p2, float z, System.Drawing.Color c1, System.Drawing.Color c2)
		{
			//
			//	0---1
			//
			VertexBuffer VertexBuffer = GetVertexBuffer(m_Device, typeof(CustomVertex.PositionColored), 2, CustomVertex.PositionColored.Format);

			CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])VertexBuffer.Lock(0,0); // Lock the buffer (which will return our structs)
			
			verts[0].Position = new Vector3(p1.X, p1.Y, z);
			verts[0].Color = c1.ToArgb();

			verts[1].Position = new Vector3(p2.X, p2.Y, z);
			verts[1].Color = c2.ToArgb();


			VertexBuffer.Unlock();

			m_Device.VertexFormat = CustomVertex.PositionColored.Format;

			// set the vertexbuffer stream source
			m_Device.SetStreamSource(0, VertexBuffer, 0, VertexInformation.GetFormatSize(CustomVertex.PositionColored.Format));
			// set fill mode
			m_Device.RenderState.FillMode = FillMode.Solid;

			m_Device.DrawPrimitives(PrimitiveType.LineStrip, 0, 1);
		}

		public override void DrawRectangle(System.Drawing.RectangleF rectangle, float z, System.Drawing.Color color, bool fill)
		{
			//
			//	0---1
			//	|	|
			//	|	|
			//	2---3
			//
			VertexBuffer VertexBuffer = GetVertexBuffer(m_Device, typeof(CustomVertex.PositionColored), 4, CustomVertex.PositionColored.Format);

			CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])VertexBuffer.Lock(0,0); // Lock the buffer (which will return our structs)
			
			int clr = color.ToArgb();

			if(fill)
			{
				verts[0].Position = new Vector3(rectangle.Left, rectangle.Top, z);
				verts[0].Color = clr;

				verts[1].Position = new Vector3(rectangle.Right, rectangle.Top, z);
				verts[1].Color = clr;

				verts[2].Position = new Vector3(rectangle.Left, rectangle.Bottom, z);
				verts[2].Color = clr;

				verts[3].Position = new Vector3(rectangle.Right, rectangle.Bottom, z);
				verts[3].Color = clr;
			}
			else
			{
				verts[0].Position = new Vector3(rectangle.Left+0.5f, rectangle.Top+0.5f, z);
				verts[0].Color = clr;

				verts[1].Position = new Vector3(rectangle.Right-0.5f, rectangle.Top+0.5f, z);
				verts[1].Color = clr;

				verts[2].Position = new Vector3(rectangle.Left+0.5f, rectangle.Bottom-0.5f, z);
				verts[2].Color = clr;

				verts[3].Position = new Vector3(rectangle.Right-0.5f, rectangle.Bottom-0.5f, z);
				verts[3].Color = clr;
			}

			VertexBuffer.Unlock();

			m_Device.VertexFormat = CustomVertex.PositionColored.Format;

			// set the vertexbuffer stream source
			m_Device.SetStreamSource(0, VertexBuffer, 0, VertexInformation.GetFormatSize(CustomVertex.PositionColored.Format));
			// set fill mode
			m_Device.RenderState.FillMode = FillMode.Solid;

			// set the indices			
			m_Device.Indices = GetDrawRectIndexBuffer(m_Device);
			
			//use the indices buffer
			if(fill)
			{
				m_Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);
			}
			else
			{
				m_Device.DrawIndexedPrimitives(PrimitiveType.LineStrip, 0, 0, 4, 6, 4);
			}
		}

		public override void DrawRectangle(System.Drawing.RectangleF rectangle, float backZ, System.Drawing.Color backColor, float foreZ, System.Drawing.Color foreColor)
		{
			VertexBuffer VertexBuffer = GetVertexBuffer(m_Device, typeof(CustomVertex.PositionColored), 4, CustomVertex.PositionColored.Format);

			CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])VertexBuffer.Lock(0,0); // Lock the buffer (which will return our structs)
			
			int clr = backColor.ToArgb();

			verts[0].Position = new Vector3(rectangle.Left, rectangle.Top, backZ);
			verts[0].Color = clr;

			verts[1].Position = new Vector3(rectangle.Right, rectangle.Top, backZ);
			verts[1].Color = clr;

			verts[2].Position = new Vector3(rectangle.Left, rectangle.Bottom, backZ);
			verts[2].Color = clr;

			verts[3].Position = new Vector3(rectangle.Right, rectangle.Bottom, backZ);
			verts[3].Color = clr;

			VertexBuffer.Unlock();

			m_Device.VertexFormat = CustomVertex.PositionColored.Format;

			// set the vertexbuffer stream source
			m_Device.SetStreamSource(0, VertexBuffer, 0, VertexInformation.GetFormatSize(CustomVertex.PositionColored.Format));
			// set fill mode
			m_Device.RenderState.FillMode = FillMode.Solid;

			// set the indices			
			m_Device.Indices = GetDrawRectIndexBuffer(m_Device);
			
			//use the indices buffer
			m_Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2);

			clr = foreColor.ToArgb();

			verts[0].Color = clr;

			verts = (CustomVertex.PositionColored[])VertexBuffer.Lock(0,0);

			verts[0].Position = new Vector3(rectangle.Left+0.5f, rectangle.Top+0.5f, foreZ);
			verts[0].Color = clr;

			verts[1].Position = new Vector3(rectangle.Right-0.5f, rectangle.Top+0.5f, foreZ);
			verts[1].Color = clr;

			verts[2].Position = new Vector3(rectangle.Left+0.5f, rectangle.Bottom-0.5f, foreZ);
			verts[2].Color = clr;

			verts[3].Position = new Vector3(rectangle.Right-0.5f, rectangle.Bottom-0.5f, foreZ);
			verts[3].Color = clr;

			VertexBuffer.Unlock();

			m_Device.DrawIndexedPrimitives(PrimitiveType.LineStrip, 0, 0, 4, 6, 4);
		}

		
		private static object g_FieldDrawImageVertxBuffer = new object();
		private static VertexBuffer GetDrawImageVertxBuffer(Microsoft.DirectX.Direct3D.Device device)
		{
			VertexBuffer _VertexBuffer = DeviceObjects[device, g_FieldDrawImageVertxBuffer] as VertexBuffer;
			if(_VertexBuffer==null)
			{
				_VertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColoredTextured), 6, device, Usage.WriteOnly | Usage.Dynamic, 0, Pool.SystemMemory);
				DeviceObjects[device, g_FieldDrawImageVertxBuffer] = _VertexBuffer;
			}
			return _VertexBuffer;
		}
		public override void DrawRectangle(System.Drawing.RectangleF rectangle, float z, Microsoft.DirectX.Direct3D.Texture texture, System.Drawing.RectangleF source, System.Drawing.Color color)
		{
			VertexBuffer _VertexBuffer = GetDrawImageVertxBuffer(m_Device);

			RenderStateManager renderState = m_Device.RenderState;

			renderState.AlphaBlendEnable = true;
			renderState.SourceBlend = Blend.SourceAlpha;
			renderState.DestinationBlend = Blend.InvSourceAlpha;
			renderState.AlphaTestEnable = true;
			renderState.ReferenceAlpha = 0x08;
			renderState.AlphaFunction = Compare.GreaterEqual;

			TextureStateManager textureState0;

			textureState0 = m_Device.TextureState[0];

			textureState0.ColorOperation = TextureOperation.Modulate;
			textureState0.ColorArgument1 = TextureArgument.TextureColor;
			textureState0.ColorArgument2 = TextureArgument.Diffuse;
			textureState0.AlphaOperation = TextureOperation.Modulate;
			textureState0.AlphaArgument1 = TextureArgument.TextureColor;
			textureState0.AlphaArgument2 = TextureArgument.Diffuse;
			textureState0.TextureCoordinateIndex = 0;
			textureState0.TextureTransform = TextureTransform.Disable; // REVIEW

			m_Device.SetTexture(0, texture);
			m_Device.VertexFormat = CustomVertex.PositionColoredTextured.Format;
			m_Device.PixelShader = null;

			CustomVertex.PositionColoredTextured[] fontVertices = new CustomVertex.PositionColoredTextured[6];

			float xpos;
			float ypos;
			float w;
			float h;

			xpos = rectangle.X;
			ypos = rectangle.Y;
			w = rectangle.Width;
			h = rectangle.Height;

			float tx1 = source.X;
			float ty1 = source.Y;
			float tx2 = tx1 + source.Width;
			float ty2 = ty1 + source.Height;

			int clr = color.ToArgb();

			fontVertices[0] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+0-0.5f,ypos+h-0.5f,z), clr, tx1, ty2);
			fontVertices[1] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+0-0.5f,ypos+0-0.5f,z), clr, tx1, ty1);
			fontVertices[2] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+w-0.5f,ypos+h-0.5f,z), clr, tx2, ty2);
			fontVertices[3] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+w-0.5f,ypos+0-0.5f,z), clr, tx2, ty1);
			fontVertices[4] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+w-0.5f,ypos+h-0.5f,z), clr, tx2, ty2);
			fontVertices[5] = new CustomVertex.PositionColoredTextured(new Vector3(xpos+0-0.5f,ypos+0-0.5f,z), clr, tx1, ty1);

			_VertexBuffer.SetData(fontVertices, 0, LockFlags.Discard);
			m_Device.SetStreamSource(0, _VertexBuffer, 0);
			m_Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
			m_Device.SetTexture(0, null);
		}


		public override void DrawEllipse(System.Drawing.RectangleF rectangle, float z, System.Drawing.Color color, int count, bool fill)
		{
			if(rectangle.Width < 0)
			{
				rectangle.Width = -rectangle.Width;
				rectangle.X = rectangle.X - rectangle.Width;
			}
			if(rectangle.Height < 0)
			{
				rectangle.Height = -rectangle.Height;
				rectangle.Y = rectangle.Y - rectangle.Height;
			}

			int cntver = count * 8;

			VertexBuffer VertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), cntver + 1 + (fill?1:0), this.m_Device, Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.SystemMemory);

			CustomVertex.PositionColored[] verts = (CustomVertex.PositionColored[])VertexBuffer.Lock(0,0); // Lock the buffer (which will return our structs)
			
			int clr = color.ToArgb();

			float w2 = rectangle.Width / 2;
			float h2 = rectangle.Height / 2;

			float x0 = rectangle.Left + w2;
			float y0 = rectangle.Top + h2;

			int s = 0;
			if(fill)
			{
				verts[0].Position = new Vector3(x0, y0, z);
				verts[0].Color = clr;
				s = 1;
			}


			for(int i=0;i<count;i++)
			{
				float x = (float)Math.Cos(Math.PI * i /(4 * count));
				float y = (float)Math.Sin(Math.PI * i /(4 * count));

				verts[s + i].Position = new Vector3(x0 + x * w2, y0 + y * h2, z);
				verts[s + i].Color = clr;

				verts[2*count + s - i - 1].Position = new Vector3(x0 + y * w2, y0 + x * h2, z);
				verts[2*count + s - i - 1].Color = clr;

				verts[2*count + s + i].Position = new Vector3(x0 - y * w2, y0 + x * h2, z);
				verts[2*count + s + i].Color = clr;

				verts[4*count + s - i - 1].Position = new Vector3(x0 - x * w2, y0 + y * h2, z);
				verts[4*count + s - i - 1].Color = clr;

				verts[4*count + s + i].Position = new Vector3(x0 - x * w2, y0 - y * h2, z);
				verts[4*count + s + i].Color = clr;

				verts[6*count + s - i - 1].Position = new Vector3(x0 - y * w2, y0 - x * h2, z);
				verts[6*count + s - i - 1].Color = clr;

				verts[6*count + s + i].Position = new Vector3(x0 + y * w2, y0 - x * h2, z);
				verts[6*count + s + i].Color = clr;

				verts[8*count + s - i - 1].Position = new Vector3(x0 + x * w2, y0 - y * h2, z);
				verts[8*count + s - i - 1].Color = clr;
			}

			verts[8*count + s].Position = new Vector3(x0 + w2, y0, z);
			verts[8*count + s].Color = clr;

			VertexBuffer.Unlock();

			m_Device.VertexFormat = CustomVertex.PositionColored.Format;

			// set the vertexbuffer stream source
			m_Device.SetStreamSource(0, VertexBuffer, 0, VertexInformation.GetFormatSize(CustomVertex.PositionColored.Format));
			// set fill mode
			m_Device.RenderState.FillMode = FillMode.Solid;

			// set the indices			
			m_Device.Indices = null;
			
			//use the indices buffer
			if(fill)
			{
				m_Device.DrawPrimitives(PrimitiveType.TriangleFan, 0, cntver);
			}
			else
			{
				m_Device.DrawPrimitives(PrimitiveType.LineStrip, 0, cntver);
			}

			VertexBuffer.Dispose();
		}

	}
}
